package com.dayu.tcp.service.server;

import com.dayu.tcp.logging.Log;
import com.dayu.tcp.logging.LogFactory;
import com.dayu.tcp.service.EventDispatcher;
import com.dayu.tcp.service.WrappedChannel;
import io.netty.channel.ChannelHandler;
import io.netty.channel.ChannelHandlerContext;
import io.netty.channel.ChannelInboundHandlerAdapter;
import lombok.NonNull;

import java.io.IOException;

/**
 * @author yehangtech
 * @date 2023/12/13 9:46
 * @description ServerDispatchHandler本质也是一个入栈处理器, 是分发事件行为的第一个入口
 */
public class ServerDispatchHandler extends ChannelInboundHandlerAdapter {

    private static final Log log = LogFactory.getLog(ServerDispatchHandler.class);

    private final EventDispatcher eventDispatcher;

    public ServerDispatchHandler(@NonNull EventDispatcher eventDispatcher) {
        this.eventDispatcher = eventDispatcher;
    }

    @Override
    public void channelActive(ChannelHandlerContext ctx) throws Exception {
        WrappedChannel channel = new WrappedChannel(ctx.channel());
        String channelId = channel.id().asShortText();
        if (log.isDebugEnabled()) {
            log.debug("Connected on channel '" + channelId + "'");
        }
        ((Server) eventDispatcher.getService()).getChannelMap().put(channelId, channel);
        eventDispatcher.dispatchChannelEvent(ctx, channel);
        super.channelActive(ctx);
    }

    @Override
    public void channelInactive(ChannelHandlerContext ctx) throws Exception {
        closeChannel(ctx);
        super.channelInactive(ctx);
    }

    @Override
    public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) throws Exception {
        String channelId = ctx.channel().id().asShortText();
        WrappedChannel channel = ((Server) eventDispatcher.getService()).getChannelMap().remove(channelId);
        if (channel != null) {
            eventDispatcher.dispatchExceptionCaught(ctx, channel, cause);
        }
        //处理IOException,主动关闭channel
        if (cause instanceof IOException) {
            ctx.close();
            closeChannel(ctx);
        }
    }

    private void closeChannel(ChannelHandlerContext ctx) {
        String channelId = ctx.channel().id().asShortText();
        WrappedChannel channel = ((Server) eventDispatcher.getService()).getChannelMap().remove(channelId);
        if (channel != null) {
            if (log.isDebugEnabled()) {
                log.debug("channel '" + channelId + "' was closed.");
            }
            eventDispatcher.dispatchChannelEvent(ctx, channel);
        }
        ctx.close();
    }

    @Override
    public void channelRead(ChannelHandlerContext ctx, Object msg) throws Exception {
        String channelId = ctx.channel().id().asShortText();
        if (log.isDebugEnabled()) {
            log.debug("Message received from channel '" + channelId + "' : '" + msg + "'.");
        }
        WrappedChannel channel = ((Server) eventDispatcher.getService()).getChannel(channelId);
        eventDispatcher.dispatchMessageEvent(ctx, channel, msg);
        super.channelRead(ctx, msg);
    }
}
